package com.haohan.cloud.framework.utils;

import com.haohan.cloud.framework.dto.Header;
import com.haohan.cloud.framework.dto.api.ApiReq;
import com.haohan.cloud.framework.dto.api.ApiResolveResp;
import com.haohan.cloud.framework.dto.api.ApiResp;
import com.haohan.cloud.framework.entity.Entry;
import com.haohan.cloud.framework.utils.TransBeanMap.DealFeild;
import com.haohan.cloud.framework.utils.http.HttpPoster;
import com.haohan.cloud.framework.utils.http.HttpUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.log4j.Logger;
import org.json.JSONObject;

import javax.servlet.ServletInputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 请求 数据获取工具类
 */
public class ReqDataUtils {


	private static Logger logger = Logger.getLogger(ReqDataUtils.class);
	/**
	 * 若为连接池 isPool设置为true
	 */
	private CloseableHttpClient httpClient;
	/**
	 * httpClient 是否为连接池
	 */
	private boolean isPool = false;


	public ReqDataUtils() {
		super();
	}

	public ReqDataUtils(CloseableHttpClient httpClient, boolean isPool) {
		super();
		this.httpClient = httpClient;
		this.isPool = isPool;
	}

	/**
	 * 解密请求数据
	 *
	 * @param req
	 */
	public static String decrypt(String data,String sercertKey) {
		if (StringUtils.isNotBlank(data)
				&& StringUtils.isBlank(sercertKey)) {
			throw new NullPointerException("String sercertKey is null");
		}
		return Des3Util.decrypt(data,sercertKey);
	}

	/**
	 * 加密请求数据
	 *
	 * @param req
	 */
	public static void encrypt(ApiReq req) {

		if (null == req) {
			throw new NullPointerException("ApiReq req is null");
		}

		String key = req.getSercertKey();

		if (StringUtils.isNotBlank(req.getData())
				&& StringUtils.isBlank(req.getSercertKey())) {
			throw new NullPointerException("String sercertKey is null");
		}

		if(StringUtils.isBlank(req.getData())){
			String data = req.toDataJson();
			if(StringUtils.isNotBlank(req.getSercertKey())){
				req.setData(Des3Util.encrypt(data, key));
			}
		}else{
			if(StringUtils.isNotBlank(req.getSercertKey())){
				req.setData(Des3Util.encrypt(req.getData(), key));
			}
		}
	}

	/**
	 * 加密返回数据
	 *
	 * @param resp
	 */
	public static void encrypt(ApiResp resp) {
		if (null == resp) {
			throw new NullPointerException("BaseResp resp is null");
		}
		String key = resp.getSercertKey();
		if ((null == resp.getApiRespData() && null != resp.getData() && !resp
				.getData().isEmpty()) && (null == key || key.isEmpty())) {
			throw new NullPointerException("String sercertKey is null");
		}
		if (null != resp.getApiRespData()) {
			String apiRespData = resp.getApiRespData().toJson();
			resp.setData(Des3Util.encrypt(apiRespData, key));
		} else if (null != resp.getData() && !resp.getData().isEmpty()) {
			resp.setData(Des3Util.encrypt(resp.getData(), key));
		}

	}

	/**
	 * 发送数据
	 *
	 * @param req
	 * @param url
	 * @return
	 */
	public ApiResolveResp sendMsg(ApiReq req, String url) {
		return sendMsg(req, url, StandardCharsets.UTF_8);
	}

	/**
	 * 发送数据
	 *
	 * @param req
	 * @param url
	 * @param encoding
	 * @return
	 */
	public ApiResolveResp sendMsg(ApiReq req, String url,
			Charset encoding) {
		return sendMsg(req, url, encoding, null);
	}

	/**
	 * 发送数据
	 *
	 * @param req
	 * @param url
	 * @param encoding
	 * @param contentType
	 * @return
	 */
	public ApiResolveResp sendMsg(ApiReq req, String url,
			Charset encoding, String contentType) {

		if (null == req) {
			throw new NullPointerException("ApiReq req is null");
		}

		if (null == url || url.isEmpty()) {
			throw new NullPointerException("String url is null");
		}

		ApiResolveResp resp = new ApiResolveResp();

		/** data节点数据加密 */
		encrypt(req);

		/** 组装请求参数*/
		List<NameValuePair> nameValueList = toNameValueList(req);

		Entry<String, String> reponse = HttpUtils.post(url, nameValueList, encoding, contentType,null!=httpClient?httpClient:HttpClients.createDefault(),isPool);

		if (reponse == null || !reponse.isSuccess() || reponse.getMsg() == null) {
			resp.error().setMsg(reponse.getMsg());;
			return resp;
		}

		String body = reponse.getMsg();
		if (StringUtils.isBlank(body)) {
			resp.error();
			return resp;
		}

		/** 请求结果解析 */
		resp = ApiResolveResp.parse(body);

		/** 校验返回结果是否加密;若加密，则解密. */
		if (resp != null && resp.getEncrypt()
				&& StringUtils.isNotBlank(resp.getData())
				&& StringUtils.isNotBlank(req.getSercertKey())) {
			resp.setData(Des3Util.decrypt(resp.getData(), req.getSercertKey()));
		}

		return resp;
	}

  /**
	* 文件专用
	* @Title: sendMsg
	* @param  req
	* @param  reqApiUrl
	* @param  reqStream
	* @return ApiResolveResp    返回类型
	* @throws
	 */
	public ApiResolveResp sendMsg(ApiReq apiReq, String reqApiUrl, ServletInputStream reqStream) {

		if (null == apiReq) {
			throw new NullPointerException("ApiReq req is null");
		}

		if (null == reqApiUrl || reqApiUrl.isEmpty()) {
			throw new NullPointerException("String reqApiUrl is null");
		}

		if (reqStream == null) {
			throw new NullPointerException("fileStream  is null");
		}

		ApiResolveResp resp = new ApiResolveResp();

		/** data节点数据加密 */
		encrypt(apiReq);

		/** 组装请求参数*/
		List<NameValuePair> nameValueList = toNameValueList(apiReq);
		if (nameValueList == null || nameValueList.size() < 1) {
			throw new NullPointerException("params  is null");
		}

		BufferedOutputStream out = null;
		BufferedInputStream in = null;
		String reponse = null;

		try {

			/** 请求参数组装 */
			JSONObject object = new JSONObject();
			for(NameValuePair tmp: nameValueList) {
				if (tmp == null) {
					continue;
				}
				object.put(tmp.getName(), tmp.getValue());
			}

			URL url = new URL(reqApiUrl);
			HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
			httpConn.setConnectTimeout(300000);
			httpConn.setReadTimeout(300000);
			httpConn.setDoOutput(true);
			httpConn.setDoInput(true);

			httpConn.setRequestMethod("POST");
			httpConn.setChunkedStreamingMode(1024);

			httpConn.setRequestProperty("UPLOAD-JSON", object.toString());
			httpConn.setRequestProperty("accept", "*/*");

			out = new BufferedOutputStream(httpConn.getOutputStream());
			byte[] buffer = new byte[1024];
			int insize = 0;

			do {
				insize = reqStream.read(buffer);
				if (insize == -1){
					break;
				}
				out.write(buffer, 0, insize);
			} while (true);

			out.flush();
			out.close();

			in = new BufferedInputStream(httpConn.getInputStream());

			reponse = HttpPoster.readByteStream(in, "UTF-8");

		} catch (Exception ex) {
			logger.error(ex.getMessage(), new Throwable(ex));
		} finally {
			try {
				if (out != null) {
					out.close();
				}
				if (in != null) {
					in.close();
				}
			} catch (IOException e) {
				logger.error(e.getMessage(), new Throwable(e));
			}
		}

		if (StringUtils.isBlank(reponse)) {
			resp.error();
			return resp;
		}

		/** 请求结果解析 */
		resp = ApiResolveResp.parse(reponse);

		/** 校验返回结果是否加密;若加密，则解密. */
		if (resp != null && resp.getEncrypt()
				&& StringUtils.isNotBlank(resp.getData())
				&& StringUtils.isNotBlank(apiReq.getSercertKey())) {
			resp.setData(Des3Util.decrypt(resp.getData(), apiReq.getSercertKey()));
		}
		return resp;
	}


	/**
	 *
	* @Title: toNameValueList
	* @param  req
	* @return List<NameValuePair>    返回类型
	* @throws
	 */
	private List<NameValuePair> toNameValueList(ApiReq req) {

		final List<NameValuePair> result = new ArrayList<NameValuePair>();

		if (req == null) {
			return result;
		}

		try {

			/** 头信息组装 */
			if (null != req.getHeader()) {

				TransBeanMap.foreachFeild(req.getHeader(), new DealFeild<Header>() {
							@Override
							public void deal(String name, Object value, Header t) {
								NameValuePair nvp = new BasicNameValuePair(name, Objects.toString(value));
								result.add(nvp);
							}
						});
			}

			/** 设备信息组装 */
			if (req.getDevice() != null) {
				NameValuePair nvp = new BasicNameValuePair("device", req.getDevice().toJson());
				result.add(nvp);
			}

			/** data节点组装 */
			if (req.getData() != null) {
				NameValuePair nvp = new BasicNameValuePair("data", req.toDataJson());
				result.add(nvp);
			}

		} catch (Exception e) {
			logger.error(e.getMessage(), new Throwable(e));
		}

		return result;
	}

}
